﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

using Ingenious.Core;
using System.Windows.Input;
using System.Collections;

namespace Ingenious.MVVM
{
    /// <summary>
    /// Base view model list
    /// </summary>
    public abstract class ViewModelList<TViewModelItem, TModelItem> : ObservableCollection<TViewModelItem>, IViewModel
        where TViewModelItem : ViewModelItem<TModelItem>
        where TModelItem : IModel
    {
        private IViewModel m_parent;
        private IObservableModelList m_modelList;
     
        #region Object Lifetime
        public ViewModelList(IViewModel parent)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }

            m_parent = parent;
        }

        public ViewModelList(IViewModel parent, IObservableModelList modelList)
            : this(parent)
        {
            if (modelList == null)
            {
                throw new ArgumentNullException("modelList");
            }

            m_modelList = modelList;

            // TODO: This should be a weak event, if we need dynamic panels
            m_modelList.CollectionChanged += OnWrapModelItem;
        }
        #endregion

        #region Command Implementation
        public virtual void OnAddCommandBindings(ICollection<CommandBinding> commandBindings)
        {
        }
        #endregion

        #region View Model Wrapping
        protected abstract TViewModelItem OnWrapModelItem(TModelItem item);

        private void OnWrapModelItem(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                IList modelList = (IList)m_modelList;
                modelList.Clear();

                foreach (TModelItem item in modelList)
                {
                    Add(OnWrapModelItem(item));
                }
            }
            else
            {
                if (e.OldItems != null)
                {
                    foreach (TModelItem item in e.OldItems)
                    {
                        Remove(OnWrapModelItem(item));
                    }
                }

                if (e.NewItems != null)
                {
                    foreach (TModelItem item in e.NewItems)
                    {
                        Add(OnWrapModelItem(item));
                    }
                }
            }
        }
        #endregion

        #region Properties
        public IViewModel Parent
        {
            get { return m_parent; }
        }

        public IModel Model
        {
            get { return m_modelList; }
        }
        #endregion
    }

}
